# str2int
#
# Module for converting binary data strings to unsigned integers
#
# BE = big endian
# LE = little endian
#
# uintB/LE and strB/LE convert between arbitrary sized ints and strings
# uintXXB/LE and strXXB/LE convert between XX-bit integers and strings
#

import struct

def uintBE(s):
    "Interpret string s as a big-endian integer"
    u = 0
    for c in s:
        u = (u << 8) + ord(c)
    return u

def uintLE(s):
    "Interpret string s as a little-endian integer"
    return sum([ord(s[i]) << (8 * i) for i in range(len(s))])

def uint32BE(s):
    "Interpret string s as a 32-bit little-endian integer"
    return struct.unpack('>L', s)[0]

def uint24BE(s):
    "Interpret string s as a 24-bit little-endian integer"
    return struct.unpack('>L', '\x00' + s)[0]

def uint16BE(s):
    "Interpret string s as a 16-bit little-endian integer"
    return struct.unpack('>H', s)[0]

def uint32LE(s):
    "Interpret string s as a 32-bit little-endian integer"
    return struct.unpack('<L', s)[0]

def uint24LE(s):
    "Interpret string s as a 24-bit little-endian integer"
    return struct.unpack('<L', s + '\x00')[0]

def uint16LE(s):
    "Interpret string s as a 16-bit little-endian integer"
    return struct.unpack('<H', s)[0]

def strBE(i, n):
    "Interpret big-endian integer i as an n-byte string"
    return ''.join([chr((i >> (8 * j)) & 0xFF) for j in range(n-1, -1, -1)])

def strLE(i, n):
    "Interpret little-endian integer i as an n-byte string"
    return ''.join([chr((i >> (8 * j)) & 0xFF) for j in range(n)])

def str32LE(u):
    "Interpret little-endian integer u as an 4-byte string"
    return struct.pack('<L', u)

def str24LE(u):
    "Interpret little-endian integer u as a 3-byte string"
    return struct.pack('<L', u)[:-1]

def str16LE(u):
    "Interpret little-endian integer u as a 2-byte string"
    return struct.pack('<H', u)

def str32BE(u):
    "Interpret big-endian integer u as an 4-byte string"
    return struct.pack('>L', u)

def str24BE(u):
    "Interpret big-endian integer u as a 3-byte string"
    return struct.pack('>L', u)[1:]

def str16BE(u):
    "Interpret big-endian integer u as a 2-byte string"
    return struct.pack('>H', u)


# Unit test
if __name__ == '__main__':
    import binascii

    for f, n in ((uintBE, 9), (uintLE, 9),\
                 (uint16LE, 2), (uint24LE, 3), (uint32LE, 4),\
                 (uint16BE, 2), (uint24BE, 3), (uint32BE, 4)):
        s = ''.join([chr(i + 16) for i in range(n)])
        u = f(s)
        print '%s("%s") = %#x' % (f.__name__, binascii.hexlify(s), u)
    
    for f, n in ((str32LE, 4), (str24LE, 3), (str16LE, 2),\
                 (str32BE, 4), (str24BE, 3), (str16BE, 2)):
        u = sum([(i + 16) << (i * 8) for i in range(n)])
        s = f(u)
        print '%s(%#x) = "%s"' % (f.__name__, u, binascii.hexlify(s))

    for f, n in ((strLE, 9), (strBE, 9)):
        u = sum([(i + 16) << (i * 8) for i in range(n)])
        s = f(u, n)
        print '%s(%#x) = "%s"' % (f.__name__, u, binascii.hexlify(s))

        
